#include <Uefi.h>             
#include <Library/PrintLib.h>
#include <Library/UefiBootServicesTableLib.h>   
#include <Protocol/DevicePath.h>   
#include <Protocol/DevicePathToText.h>  
#include <Protocol/DiskIo.h>

EFI_STATUS
PrintNode(EFI_DEVICE_PATH_PROTOCOL *Node)
{
  Print(L"Node Type: %d, SubType: %d, Length: %d\n", Node->Type, Node->SubType, Node->Length);
  return EFI_SUCCESS;
}

EFI_DEVICE_PATH_PROTOCOL *
WalkthroughDevicePath(EFI_DEVICE_PATH_PROTOCOL *DevicePath, EFI_STATUS (*Callback)(EFI_DEVICE_PATH_PROTOCOL*))
{
  EFI_DEVICE_PATH_PROTOCOL *Node = DevicePath;
  while (!IsDevicePathEnd(Node)) {

    Callback(Node);
    Node = NextDevicePathNode(Node);
  }

  return Node;
}

EFI_STATUS
UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  EFI_STATUS Status                                     = EFI_SUCCESS;
  UINTN HandleIndex                                     = 0;
  UINTN NumHandles                                      = 0;
  EFI_HANDLE *ControllerHandle                          = NULL;
  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *Device2TextProtocol = NULL;

  Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&Device2TextProtocol);
  if (EFI_ERROR(Status)) {

    Print(L"Failed to locate DevicePathToText protocol: %r\n", Status);
    return Status;
  }

  Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &NumHandles, &ControllerHandle);
  if (EFI_ERROR(Status)) {

    Print(L"Failed to locate handles with DiskIo protocol: %r\n", Status);
    return Status;
  }

  for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {
    
    EFI_DEVICE_PATH_PROTOCOL *DevicePath = NULL;
    Status                               = gBS->HandleProtocol(ControllerHandle[HandleIndex], &gEfiDevicePathProtocolGuid, (VOID**)&DevicePath);
    if (EFI_ERROR(Status)) {

      Print(L"Failed to get DevicePath protocol for handle %d: %r\n", HandleIndex, Status);
      continue;
    }

    CHAR16 *DevicePathText = Device2TextProtocol->ConvertDevicePathToText(DevicePath, TRUE, TRUE);
    if (DevicePathText != NULL) {

      Print(L"Device Path for handle %d: %s\n", HandleIndex, DevicePathText);
      FreePool(DevicePathText);
    } else {
      
      Print(L"Failed to convert device path to text for handle %d\n", HandleIndex);
    }

    WalkthroughDevicePath(DevicePath, PrintNode);
    Print(L"\n\n");
  }

  return EFI_SUCCESS;
}